package com.zu.commu.remote.session;

import com.zu.commu.context.ServerContext;
import com.zu.commu.exception.CommuException;
import com.zu.commu.interf.Order;
import com.zu.commu.remote.RemoteServer;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

public class Session {
	private HashMap<String, Object> attributes;

	public Session(SocketChannel ch) {
		//属性集合
		this.attributes = new HashMap<String, Object>();
		//默认GPSS是在线的
		this.attributes.put("GPRSIsOnLine", new Boolean(true));
		//GPRS不是关闭的
		this.attributes.put("GPRSIsClosed", new Boolean(false));
		//连接的实例
		this.attributes.put("GPRSChannel", ch);
		//心跳时间为当前
		this.attributes.put("GPRSHeartBeatTime", new Long(System.currentTimeMillis()));
		//命令集合
		this.attributes.put("GPRSCommands", new ArrayList());
	}

	@Override
	public String toString() {
		return "Session [attributes=" + attributes + "]";
	}

	public void setAttribute(String key, Object o) {
		this.attributes.put(key, o);
	}

	public Object getAttribute(String key) {
		return this.attributes.get(key);
	}

	/**
	 * 关闭现有的连接
	 * 这样此连接将从RemoteServer.getSelector()中取消
	 * SocketChannel.finishConnect(); 
	 * SocketChannel.socket().close();
	 * SocketChannel.close();
	 */
	public void close() {
		Object o = getAttribute("GPRSChannel");
		if (o != null)
			closeChannel((SocketChannel) o);
	}
	/**
	 * 关闭现有的连接
	 * 这样此连接将从RemoteServer.getSelector()中取消
	 * SocketChannel.finishConnect(); 
	 * SocketChannel.socket().close();
	 * SocketChannel.close();
	 */
	private void closeChannel(SocketChannel ch) {
		this.attributes.put("GPRSIsOnLine", new Boolean(false));
		this.attributes.put("GPRSIsClosed", new Boolean(true));
		try {
			SelectionKey seleKey = ch.keyFor(RemoteServer.getSelector());
			if (seleKey != null) {
				seleKey.cancel();
			}
			ch.finishConnect();
			ch.socket().close();
			ch.close();
		} catch (Exception localException) {
		}
	}

	/**
	 * 读取数据
	 * @return
	 * @throws CommuException
	 */
	public byte[] read() throws CommuException {
		Object o = getAttribute("GPRSChannel");
		if (o != null) {
			SocketChannel ch = (SocketChannel) o;
			synchronized (ch) {
				ByteBuffer buffer = ByteBuffer.allocate(ServerContext.bufferSizeForReadRemoteSocket);
				byte[] bytes = (byte[]) null;
				CommuException ex = null;
				//如果已经连接
				if (ch.isConnected())
					try {
						if (ch.read(buffer) == -1) {
							ex = new CommuException().setMessage("远程正常关闭了Socket连接！", null);
						}
						if (buffer.position() != 0) {
							bytes = new byte[buffer.position()];
							System.arraycopy(buffer.array(), 0, bytes, 0, bytes.length);
						}
					} catch (IOException e) {
						ex = new CommuException().setMessage("读取数据出现异常！" + e.getMessage(), e);
					}
				else {
					ex = new CommuException().setMessage("SocketChannel不能正常连接！", null);
				}
				if (ex != null) {
					closeChannel(ch);
					throw ex;
				}
				return bytes;
			}
		}

		throw new CommuException().setMessage("不存在这个连接，所以不能检测其是否正常连接！", null);
	}

	/**
	 * 写数据
	 * @param buf 字节组
	 * @throws CommuException
	 */
	public void write(byte[] buf) throws CommuException {
		if (buf == null) {
			throw new CommuException().setMessage("出错！向远端模块发送的数据为空。", null);
		}
		ByteBuffer buffer = ByteBuffer.allocateDirect(buf.length);
		buffer.clear();
		buffer.put(buf);
		buffer.flip();
		Object o = getAttribute("GPRSChannel");
		if (o != null) {
			SocketChannel ch = (SocketChannel) o;
			synchronized (ch) {
				try {
					SelectionKey seleKey = ch.keyFor(RemoteServer.getSelector());
					if (seleKey == null) {
						throw new CommuException().setMessage("网络写数据出错！没有得到连接通道的键值！", null);
					}
					int count = 0;
					while (!seleKey.isWritable()) {
						count++;
						try {
							Thread.sleep(10L);
						} catch (Exception localException1) {
						}
						if (count > 50)
							break;
					}
				} catch (Exception e) {
					throw new CommuException().setMessage("出错！向远端模块发送的数据出生异常！" + e.getMessage(), e);
				}
				try {
					ch.write(buffer);
				} catch (IOException e) {
					throw new CommuException().setMessage("出错！向远端模块发送的数据出生异常！", e);
				}
			}
		}
	}

	public void refreshHeartBeatTime() {
		this.attributes.put("GPRSIsOnLine", new Boolean(true));
		this.attributes.put("GPRSIsClosed", new Boolean(false));
		this.attributes.put("GPRSHeartBeatTime", new Long(System.currentTimeMillis()));
	}

	public void putInCommandId(String commandId, Order order) {
		ArrayList list = (ArrayList) this.attributes.get("GPRSCommands");
		synchronized (list) {
			list.add(new CommandNode(commandId, order));
		}
	}

	public String[] putOutCommandId(Order order) {
		String[] commandIds = (String[]) null;

		if (order.equals(Order.COMMON)) {
			String firstCommandId = getAndRemoveFirstCommandId();
			if (firstCommandId != null) {
				commandIds = new String[1];
				commandIds[0] = firstCommandId;
			} else {
				commandIds = (String[]) null;
			}
			return commandIds;
		}

		ArrayList temp = new ArrayList();
		ArrayList list = (ArrayList) this.attributes.get("GPRSCommands");
		synchronized (list) {
			Iterator it = list.iterator();
			CommandNode cnode = null;
			while (it.hasNext()) {
				cnode = (CommandNode) it.next();
				if ((!cnode.order.equals(order)) && ((!order.equals(Order.PUMP)) || (!cnode.order.equals(Order.SETCLOSEPUMP_2_0))) && ((!order.equals(Order.PUMP)) || (!cnode.order.equals(Order.SETOPENPUMP_2_0))) && ((!order.equals(Order.CALL)) || (!cnode.order.equals(Order.READDATA_2_0))) && ((!order.equals(Order.SETCLOCK)) || (!cnode.order.equals(Order.SETCLOCK_2_0))) && ((!order.equals(Order.SETCLOCK)) || (!cnode.order.equals(Order.SETCLOCK_2_0))) && ((!order.equals(Order.READCLOCK)) || (!cnode.order.equals(Order.READCLOCK_2_0))) && ((!order.equals(Order.INITVALUE)) || (!cnode.order.equals(Order.SETINITVALUE_2_0))) && ((!order.equals(Order.CHARGE)) || (!cnode.order.equals(Order.SETCHARGE_2_0))) && ((!order.equals(Order.READCHARGE)) || (!cnode.order.equals(Order.READCHARGE_2_0)))
						&& ((!order.equals(Order.CLEANALL)) || (!cnode.order.equals(Order.SETCLEAN_2_0))) && ((!order.equals(Order.WATERWARNING)) || (!cnode.order.equals(Order.SETWATERREMAINWARNING_2_0))) && ((!order.equals(Order.WATERLEVEL)) || (!cnode.order.equals(Order.SETWATERLEVELOPTION_2_0))))
					continue;
				temp.add(cnode.commandId);
				if (cnode.order.IsMulRresult()) {
					cnode.genTime = System.currentTimeMillis();
				} else {
					it.remove();
				}
			}
		}

		if (temp.size() > 0) {
			commandIds = new String[temp.size()];
			for (int i = 0; i < temp.size(); i++) {
				commandIds[i] = ((String) temp.get(i));
			}
		}
		return commandIds;
	}

	private String getAndRemoveFirstCommandId() {
		ArrayList list = (ArrayList) this.attributes.get("GPRSCommands");
		if ((list == null) || (list.size() == 0)) {
			return null;
		}
		CommandNode cnode = (CommandNode) list.get(0);
		if (cnode == null) {
			return null;
		}
		list.remove(0);
		return cnode.commandId;
	}

	public boolean isExistCommandId(String commandId) {
		ArrayList list = (ArrayList) this.attributes.get("GPRSCommands");
		boolean flag = false;
		Iterator it = list.iterator();
		CommandNode cnode = null;
		while (it.hasNext()) {
			cnode = (CommandNode) it.next();
			if (cnode == null) {
				break;
			}
			if ((cnode.commandId != null) && (cnode.commandId.equals(commandId))) {
				flag = true;
				break;
			}
		}
		return flag;
	}
}
